#include "RbnGenome.h"

#include "../../../base.h"
#include "../../../math/Random.h"

#include "RbnGenomeNode.h"


namespace GA {

/*
	RbnGenome
*/

/*	public	*/

RbnGenome* RbnGenome::newRandom(int nInputs, int nNodes, int k) {

	/* nodes : init */
	RbnGenomeNode** nodes = new RbnGenomeNode*[nNodes];

	/* nodes : fill */
	for(int i = 0; i != nNodes; ++i) {
		nodes[i] = RbnGenomeNode::newRandom(nInputs + nNodes, k);
	}

	/* new genome */
	return new RbnGenome(nInputs, nNodes, nodes);
}

RbnGenome::RbnGenome(const RbnGenome& genome) :
	Genome(),
	_nInputs(genome._nInputs),
	_nNodes(genome._nNodes) {
		
	/* nodes count */
	int nNodes = _nNodes;

	/* nodes : init */
	RbnGenomeNode** nodes = new RbnGenomeNode*[nNodes];

	/* nodes : fill */
	RbnGenomeNode** originalNodes = genome._nodes;
	for(int i = 0; i != nNodes; ++i) {
		nodes[i] = originalNodes[i]->copy();
	}

	/* nodes : assign */
	_nodes = nodes;
}

RbnGenome::~RbnGenome() {
	/* nodes */
	deleteall<RbnGenomeNode>(_nodes, _nNodes);
	delete[] _nodes;
}

RbnGenome* RbnGenome::copy() const {
	/* new genome */
	return new RbnGenome(*this);
}

Genome* RbnGenome::crossover(Genome const& genome) const {
	/* RBN genome */
	RbnGenome const& rbnGenome = static_cast<RbnGenome const&>(genome);

	assert(_nInputs == rbnGenome._nInputs);
	assert(_nNodes == rbnGenome._nNodes);

	/* nNodes */
	int nNodes = _nNodes;

	/* nodes : init */
	RbnGenomeNode** nodes = new RbnGenomeNode*[nNodes];

	/* nodes crossover point */
	int point = Random::getInstance().getInt(nNodes);

	/* nodes : copy first bit */
	for(int i = 0; i != point; ++i) {
		nodes[i] = _nodes[i]->copy();
	}

	/* nodes : copy second bit */
	for(int i = point; i != nNodes; ++i) {
		nodes[i] = rbnGenome._nodes[i]->copy();
	}

	RbnGenome* result = new RbnGenome(_nInputs, nNodes, nodes);

	return result;
}

void RbnGenome::mutate(double geneMutationProbability) {
	/* random */
	Random& random = Random::getInstance();

	/* mutate nodes */
	int nNodes = _nNodes;
	for(int i = 0; i != nNodes; ++i) {
		/* mutate this node ? */
		if (random.getBool(geneMutationProbability)) {
			/* yes */
			_nodes[i]->mutate(nNodes);
		}
	}
	//TODO mutate add/delete node
}

Rbn* RbnGenome::getNewRbn() const {
	/* nodes count */
	int nNodes = _nNodes;
	
	/* rbn nodes : init */
	RbnNode** nodes = new RbnNode*[nNodes];

	/* rbn nodes : fill */
	for(int i = 0; i != nNodes; ++i) {
		nodes[i] = _nodes[i]->getNewRbnNode();
	}

	/* new rbn */
	return new Rbn(_nInputs, nNodes, nodes);
}


/*	private	*/

RbnGenome::RbnGenome(int nInputs, int nNodes, RbnGenomeNode** nodes) :
	Genome(),
	_nInputs(nInputs),
	_nNodes(nNodes),
	_nodes(nodes) {}

} // GA

